/*********************************************************************************
 *      Copyright:  (C) 2023 Xie Mujie<1289180278@qq.com>  Zhu Lijun<326246597@qq.com>
 *                  All rights reserved.
 *
 *       Filename:  main.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(07/01/23)
 *         Author:  Zhu Lijun<3262465970@qq.com> Xie Mujie<1289180278@qq.com>
 *      ChangeLog:  1, Release initial version on "07/01/23 08:50:12"
 *                 
 ********************************************************************************/

#include "main.h"


#define BLE_ADDR         "A0:76:4E:59:57:12"
#define PTHREAD_SIZE     4*1024


pthread_t             ble_wr_tid;
pthread_t             mqtt_tid;
gatt_connection_t    *conn = NULL;

static GMainLoop *m_main_loop;
static void notification_handler(const uuid_t* uuid, const uint8_t* data, size_t data_length, void* user_data);



static void on_user_abort(int arg) 
{
	g_main_loop_quit(m_main_loop);
}


int main(int argc, char **argv)
{
	char                 *conf_file_name = CONFNAME;
	char                 *ble_addr = BLE_ADDR;
	int                   ch;
	int                   rv;
	void                 *adapter;
	const char           *adapter_name = NULL;
	int                   temp;
	double                last_time = 0;
	double                current_time = 0;
	char                  date_time[30] = {0};
	const char           *nt_uuid = "c305";
	const char           *wr_uuid = "c304";
	pthread_attr_t        thread_attr, atr;
	static uuid_t         notify_uuid;
	static uuid_t         write_uuid;
	struct mqtt_conf_s    conn_par;


	struct option         opts[] = {
		{"conf.json", no_argument, NULL, 'f'},
		{"ble_mac", no_argument, NULL, 'm'},
		{"help", no_argument, NULL, 'H'},
		{NULL, 0, NULL, 0}
	};

	while (-1 != (ch = getopt_long(argc, argv, "f:m:H", opts, NULL)))
	{
		switch(ch)
		{
			case 'f':
				conf_file_name = optarg;
				break;
			case 'm':
				ble_addr = optarg;
				break;
			case 'H':
				//print_usage(argv[0]);
				return 0;
		}
	}

	//Parsing conf.json parameters
	memset(&conn_par, 0, sizeof(conn_par));
	if (pari_conf_json(conf_file_name, &conn_par) < 0)
	{
		log_error("open or paring conf.json failure!");
		return -1;
	}

	//init log
	if (log_init(conn_par.log_path, LOG_LEVEL_DEBUG) < 0)
	{
		log_error("LOG init failure!");
		return -2;
	}

	//thread worker1(ble write) init
	if (pthread_attr_init(&thread_attr) )
	{
		log_error("ble pthread_attr_init() failure: %s", strerror(errno));
		return -3;
	}

	//set thread worker1 detach mode
	if ( pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) )
	{
		log_error("pthread_attr_setdetachstate() failure: %s", strerror(errno));
		return -4;
	}

	//thread worker2(mqtt) init	
	if( pthread_attr_init(&atr))
	{
		log_error("mqtt pthread_addr_init failure");
		return -5;
	}

	//set thread worke2 detach mode
	if (pthread_attr_setdetachstate(&atr, PTHREAD_CREATE_DETACHED) < 0)
	{
		log_error("mqtt pthread_addr_setdetachstate failure: %s", strerror(errno));
		return -7;
	}

    	//create thread worker1(ble write)
	if (pthread_create(&ble_wr_tid, &thread_attr, thread_worker1_ble_wr, (void *)conn))
	{
		log_error("ble write pthread_create failure: %s", strerror(errno));
		return -8;
	}
	log_info("create ble write pthread successfully");

	//create thread worker2(mqtt)	
	if (pthread_create(&mqtt_tid, &atr, thread_worker2_mqtt, &conn_par))
	{
		log_error("mqtt pthread_create failure: %s", strerror(errno));
		return -9;
	}
	log_info("create mqtt pthread successfully");
	/* end thread create */


	/* main thread */

	//scan BLE 
	lescan_init(adapter, adapter_name);

	//try to connect the BLE until timeout
	while (1)
	{
		conn = gattlib_connect(NULL, ble_addr, GATTLIB_CONNECTION_OPTIONS_LEGACY_DEFAULT);
		if (conn == NULL)
		{
			log_error("Fail to connect to the bluetooth device : %s\n", strerror(errno));
		}
		else
		{
			ble_conn_flag = 1;
			break;
		}

		sleep(1);
	}
	log_info("Connect to BLE devices %s successfully\n", ble_addr);


	/* ready to notify */

	signal(SIGINT, on_user_abort);

    //turn the string type to uuid_t type
	if (gattlib_string_to_uuid(nt_uuid, strlen(nt_uuid) + 1, &notify_uuid) < 0)
	{
		log_error("notification_string_uuid turn to uuid_t failed: %s", strerror(errno));
		gattlib_disconnect(conn);
	}
	if (gattlib_string_to_uuid(wr_uuid, strlen(wr_uuid) + 1, &write_uuid) < 0)
	{
		log_error("write_uuid_string turn to uuid_t failed: %s", strerror(errno));
		gattlib_disconnect(conn);
	}

    //register a notification
	gattlib_register_notification(conn, notification_handler, NULL);

	temp = gattlib_notification_start(conn, &notify_uuid);
	if (temp) 
	{
		log_error("Fail to start notification: %s", strerror(errno));
		gattlib_disconnect(conn);
	}

	m_main_loop = g_main_loop_new(NULL, 0);
	g_main_loop_run(m_main_loop);

	gattlib_notification_stop(conn, &notify_uuid);
	g_main_loop_unref(m_main_loop);
	
    //disconnect the BLE
	gattlib_disconnect(conn);

    //destroy pthread
	pthread_attr_destroy(&thread_attr);
	pthread_attr_destroy(&atr);

	log_info("Normally exit\n");

	return 0;
}



static void notification_handler(const uuid_t* uuid, const uint8_t* data, size_t data_length, void* user_data)
{
	int i;
	char *pu_buf;
	
	pu_buf = (char *)data;
	enqueue(pu_buf);
	pthread_kill(mqtt_tid, SIGUSR2);
	
#if 0
	if (data[data_length - 1] == 'q')
	{
		printf("ESP32 ready to quit\n");
		kill(getpid(),SIGINT);
		return ;
	}
#endif

}
